Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve assert_eq! and assert_ne! #79100

Merged
merged 6 commits into from
Feb 21, 2021
Merged

Conversation

a1phyr
Copy link
Contributor

@a1phyr a1phyr commented Nov 16, 2020

This PR improves assert_eq! and assert_ne! by moving the panicking code in an external function.

It does not change the fast path, but the move of the formatting in the cold path (the panic) may have a positive effect on in instruction cache use and with inlining.

Moreover, the use of trait objects instead of generic may improve compile times for assert_eq!-heavy code.

Godbolt link: https://rust.godbolt.org/z/TYa9MT
Updated: https://rust.godbolt.org/z/bzE84x

@rust-highfive
Copy link
Collaborator

r? @cramertj

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 16, 2020
@pickfire
Copy link
Contributor

pickfire commented Nov 16, 2020

Does this improves runtime performance?

Godbolt link: https://rust.godbolt.org/z/TYa9MT

I can't seemed to notice the difference in the assembly.

Moreover, the use of trait objects instead of generic may improve compile times for assert_eq!-heavy code.

Looks nice but I wonder if we need 2x/4x the trait objects? Is it possible to have one <T, U> (merged both assert_eq! and assert_ne! but with different output string) and maybe another one for Arguments (I am not sure if we can merge this too)?

@a1phyr
Copy link
Contributor Author

a1phyr commented Nov 16, 2020

I can't seemed to notice the difference in the assembly.

The difference is not in the fast path, but in the panicking one.

Looks nice but I wonder if we need 2x/4x the trait objects? Is it possible to have one <T, U> (merged both assert_eq! and assert_ne! but with different output string) and maybe another one for Arguments (I am not sure if we can merge this too)?

The only formatting that change between assert_eq! and assert_ne! is that (left == right) becomes (left != right). We could eventually give the comparison operator as parameter to assert_eq_failed.

@pickfire
Copy link
Contributor

pickfire commented Nov 16, 2020

Looks nice but I wonder if we need 2x/4x the trait objects? Is it possible to have one <T, U> (merged both assert_eq! and assert_ne! but with different output string) and maybe another one for Arguments (I am not sure if we can merge this too)?

The only formatting that change between assert_eq! and assert_ne! is that (left == right) becomes (left != right). We could eventually give the comparison operator as parameter to assert_eq_failed.

Yes, but doesn't the current implementation makes it another function which doubles the code if a user use assert_eq! and assert_ne! on the same T and U?

Not sure about the Arguments case since I am not sure if that could be optimized into a separate function.

@pickfire
Copy link
Contributor

I can't seemed to notice the difference in the assembly.

The difference is not in the fast path, but in the panicking one.

Diffing the two assembly outputs seemed to give me nothing, are you sure you posted the correct link? Or maybe I copied the wrong thing?

@a1phyr
Copy link
Contributor Author

a1phyr commented Nov 16, 2020

The only formatting that change between assert_eq! and assert_ne! is that (left == right) becomes (left != right). We could eventually give the comparison operator as parameter to assert_eq_failed.

Yes, but doesn't the current implementation makes it another function which doubles the code if a user use assert_eq! and assert_ne! on the same T and U?

Yes, it does. We can add an operator parameter, which is equal to == for assert_eq! and != for assert_ne!, and use it for the formatting later.

Not sure about the Arguments case since I am not sure if that could be optimized into a separate function.

Well, it could, but we definitely want to keep a separate generic function when there is no Argument, because it has to be created in the function calling assert_eq, and we want the generated code here as thin as possible. IMHO it is not worth the trouble.

@a1phyr
Copy link
Contributor Author

a1phyr commented Nov 16, 2020

Diffing the two assembly outputs seemed to give me nothing, are you sure you posted the correct link? Or maybe I copied the wrong thing?

You don't have any difference between old_basic and new_basic ? Or between old_args and new_args ? Weird... I checked the link, it works on bot my computer and my phone.

@andjo403
Copy link
Contributor

think that @pickfire expected something like this https://rust.godbolt.org/z/4co4f1 where there is a diff between two editors that implement the same thing in two ways. I think that I split @a1phyr:s example correct in that godbolt link.

@a1phyr
Copy link
Contributor Author

a1phyr commented Nov 16, 2020

@andjo403 Oh, I see. I didn't know you could produce diffs like that in Godbold.

@a1phyr a1phyr force-pushed the better_assert_eq branch 2 times, most recently from 0c9f27d to 5d79f11 Compare November 16, 2020 23:30
@a1phyr
Copy link
Contributor Author

a1phyr commented Nov 17, 2020

This is very strange, some tests fail but seem totally unrelated (eg this test), and I'm not sure what to do about them.

Anyway, let's see if it improves compile time

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Insufficient permissions to issue commands to rust-timer.

@bors
Copy link
Contributor

bors commented Nov 17, 2020

@a1phyr: 🔑 Insufficient privileges: not in try users

1 similar comment
@bors
Copy link
Contributor

bors commented Nov 17, 2020

@a1phyr: 🔑 Insufficient privileges: not in try users

@rust-timer
Copy link
Collaborator

Insufficient permissions to issue commands to rust-timer.

@pickfire
Copy link
Contributor

@andjo403 Oh, I didn't know you can produce diff in godbolt.

It seemed like the assembly lines increased.

@pickfire
Copy link
Contributor

Updated godbolt to include 6 functions, it seemed like the number of assembly lines increased, removing #[track_caller] can slightly reduce it (380 vs 512). https://rust.godbolt.org/z/EsGWbG

Merging the one with Arguments into the same function seemed to produce a slightly more lines of assembly (512 -> 540). https://rust.godbolt.org/z/a7rqrj

@a1phyr
Copy link
Contributor Author

a1phyr commented Nov 18, 2020

Can someone start rust-timer to see if this has a positive impact on build time ?

And also, does someone has a clue what makes this test fail ? It does not seem related to my changes.

@pickfire
Copy link
Contributor

@jyn514

@jyn514
Copy link
Member

jyn514 commented Nov 18, 2020

@pickfire please don't ping me specifically for perf runs, there's a Zulip stream for that.

@a1phyr are you sure it makes sense to measure the perf before fixing the tests? Your fix might itself have a perf impact.

@a1phyr
Copy link
Contributor Author

a1phyr commented Nov 18, 2020

I think the only changes that I have left to do are tests themselves (eg changing a mir output), but you're right that we should wait them to be fixed.

@jyn514
Copy link
Member

jyn514 commented Nov 18, 2020

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@bors
Copy link
Contributor

bors commented Nov 18, 2020

⌛ Trying commit 0dbf6d0f280da53dfadc453a699d01b577a33a4b with merge 7827eb84fe5a82fab0dcc16f6eb5121188f2846e...

@tmiasko
Copy link
Contributor

tmiasko commented Feb 14, 2021

Looking at last bors failure, it is likely that you will have to set profiler = true in config.toml and additionally bless run-make-fulldeps tests with ./x.py test src/test/run-make-fulldeps/ --bless.

@a1phyr
Copy link
Contributor Author

a1phyr commented Feb 16, 2021

Thanks ! I didn't know about the profiler config, so I thought the issue only happened on msvc target.

The test should pass now.

@a1phyr
Copy link
Contributor Author

a1phyr commented Feb 20, 2021

@m-ou-se I don't think I can retry myself, could you do it please ?

@m-ou-se
Copy link
Member

m-ou-se commented Feb 20, 2021

Oh sorry, missed your previous message.

@bors r+ rollup=maybe

@bors
Copy link
Contributor

bors commented Feb 20, 2021

📌 Commit 7333759 has been approved by m-ou-se

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 20, 2021
@panstromek
Copy link
Contributor

Note: this should probably be rollup=never, it affects perf

@jyn514
Copy link
Member

jyn514 commented Feb 20, 2021

@bors rollup=never

@jyn514
Copy link
Member

jyn514 commented Feb 20, 2021

also @m-ou-se rollup=maybe is not the same as rollup=iffy, it's the same as not adding rollup at all: https://forge.rust-lang.org/compiler/reviews.html#rollups

@m-ou-se
Copy link
Member

m-ou-se commented Feb 20, 2021

Oh I'm aware of rollup=maybe undoing the rollup command, but I didn't mean to apply it to this PR though. Looks like I got it mixed up with another PR I was looking at while trying to multitask, oops. Thanks for catching my mistake, @panstromek.

@bors
Copy link
Contributor

bors commented Feb 21, 2021

⌛ Testing commit 7333759 with merge ed58a2b...

@bors
Copy link
Contributor

bors commented Feb 21, 2021

☀️ Test successful - checks-actions
Approved by: m-ou-se
Pushing ed58a2b to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Feb 21, 2021
@bors bors merged commit ed58a2b into rust-lang:master Feb 21, 2021
@rustbot rustbot added this to the 1.52.0 milestone Feb 21, 2021
@rust-log-analyzer
Copy link
Collaborator

A job failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at ed58a2b03 Auto merge of #79100 - a1phyr:better_assert_eq, r=m-ou-se
##[group]Run src/ci/publish_toolstate.sh
src/ci/publish_toolstate.sh
env:
  SCCACHE_BUCKET: rust-lang-ci-sccache2
  DEPLOY_BUCKET: rust-lang-ci2
  TOOLSTATE_REPO: https://github.com/rust-lang-nursery/rust-toolstate
---
  CACHE_DOMAIN: ci-caches.rust-lang.org
  TOOLSTATE_REPO_ACCESS_TOKEN: ***
##[endgroup]
Cloning into 'rust-toolstate'...
/home/runner/work/rust/rust/src/tools/publish_toolstate.py:121: DeprecationWarning: 'U' mode is deprecated
📣 Toolstate changed by rust-lang/rust#79100!
  with open(path, 'rU') as f:

Tested on commit rust-lang/rust@ed58a2b03b6284b070fae2349898b16df98b7765.
Direct link to PR: <https://github.com/rust-lang/rust/pull/79100>

🎉 miri on windows: test-fail → test-pass (cc @oli-obk @eddyb @RalfJung).
🎉 miri on linux: test-fail → test-pass (cc @oli-obk @eddyb @RalfJung).
Traceback (most recent call last):
Traceback (most recent call last):
  File "/home/runner/work/rust/rust/src/tools/publish_toolstate.py", line 338, in <module>
    response = urllib2.urlopen(urllib2.Request(
  File "/usr/lib/python3.8/urllib/request.py", line 222, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/lib/python3.8/urllib/request.py", line 522, in open
    req = meth(req)
  File "/usr/lib/python3.8/urllib/request.py", line 1281, in do_request_
    raise TypeError(msg)
TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.
##[error]Process completed with exit code 1.

Some(args) => panic!(
r#"assertion failed: `(left {} right)`
left: `{:?}`,
right: `{:?}: {}`"#,
Copy link

@ghost ghost Mar 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the change that moves : {} inside the ` quotes intentional?

The panic message now looks suboptimal to me: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=0cbe6c5669d0b7458c6d9f67a3ea7518

Nightly
 right: `3: 1 + 1 should definitely be 3`', src/main.rs:2:5
Stable
 right: `3`: 1 + 1 should definitely be 3', src/main.rs:2:5

(In case it was unintentional, I have a patch.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hyd-dev oh, good catch! Can you send that patch as a PR? (Feel free to assign me with r? @m-ou-se.)

Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Mar 13, 2021
Fix panic message of `assert_failed_inner`

cc rust-lang#79100 (comment)

r? `@m-ou-se`
JohnTitor added a commit to JohnTitor/rust that referenced this pull request Mar 14, 2021
Fix panic message of `assert_failed_inner`

cc rust-lang#79100 (comment)

r? ``@m-ou-se``
bors added a commit to rust-lang-ci/rust that referenced this pull request Mar 20, 2021
Debug-print result when an unstable fingerprint is detected

Helps with issues like rust-lang#83311

I had previously tried to do this in rust-lang#80692, but it had a significant performance impact (even though the code was never actually run). Hopefully, this will be better now that rust-lang#79100 has been merged.
@a1phyr a1phyr deleted the better_assert_eq branch March 12, 2024 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-slow Issue: Problems and improvements with respect to performance of generated code. merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.